﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Collections.Generic;
using System.Threading;
using Qplus.Infrastructure;
using System.Collections.ObjectModel;

using System.Diagnostics;
using Qplus.enums;

namespace Qplus.protocol
{

    class SizeQueue<T>
    {
        private readonly Queue<T> queue = new Queue<T>();
        private readonly int maxSize;
        public SizeQueue(int maxSize) { this.maxSize = maxSize; }

        public void myEnqueue(T item)
        {
            lock (queue)
            {
                while (queue.Count >= maxSize)
                {
                    Monitor.Wait(queue);
                }
                queue.Enqueue(item);
                if (queue.Count == 1)
                {
                    // wake up any blocked dequeue
                    Monitor.PulseAll(queue);
                }
            }
        }
        public T myDequeue()
        {
            lock (queue)
            {
                while (queue.Count == 0)
                {
                    Monitor.Wait(queue);
                }
                T item = queue.Dequeue();
                if (queue.Count == maxSize - 1)
                {
                    // wake up any blocked enqueue
                    Monitor.PulseAll(queue);
                }
                return item;
            }
        }
    }


    public class PacketQueue : IPacketListener
    {
        const long TIMEOUT = 30000;
        private TcpTransport tcp;

        //发送队列
        Queue<OutPacket> sendList;
        //接收队列
        Queue<InPacket> receiveList;

        //线程池一次只能执行一个线程
        SingleExecutor sendExcutor;
        SingleExecutor receiveExcutor;
        AutoResetEvent sendEvent , receiveEvent;

        private List<IPacketListener> packetListener;

        public PacketQueue()
        {
            sendList = new Queue<OutPacket>();
            sendEvent = new AutoResetEvent(true);
            receiveEvent = new AutoResetEvent(true);
           // sendList = Queue<OutPacket>.Synchronized(new Queue<OutPacket>());
            receiveList = new Queue<InPacket>();

            sendExcutor = new SingleExecutor();
            receiveExcutor = new SingleExecutor();
            packetListener = new List<IPacketListener>();
            packetListener.Add(this);
        }

        public  void addPacketListener(IPacketListener l){
		    if(packetListener.Contains(l))
            {
			    return;
		    }
		    packetListener.Add(l);
	    }

        /**
	    * 设置连接
	    * @param tcp
	    */
        public void setConnection(TcpTransport tcp)
        {
            this.tcp = tcp;
        }


        /**
	    * 将数据包放入发送队列
	    * @param packet
	    */
        public void putOut(OutPacket packet)
        {
            sendEvent.WaitOne();
            sendEvent.Reset();
            
            try
            {
                sendList.Enqueue(packet);
            }
            catch (InvalidCastException e)
            {
                Debug.WriteLine(e.Message);
            }
            sendExcutor.submit(new WaitCallback(SendCall));
            
            sendEvent.Set();
        }


        //static int i = 0;
	    /**
	     * 解析数据回调
	     */
	    private void triggerReceive()
        {
		    InPacket p = null;
            while (receiveList.Count > 0)
            {
                p = receiveList.Dequeue();
                if (p == null)
                    continue;
                try
                {
                    byte[] data = p.getData();
                    p.handle(data, 0, data.Length);
                    PacketEvent pevent = new PacketEvent();
                    pevent.myPacket = p;
                    for (int i = 0; i < packetListener.Count; i++)
                    {
                        packetListener[i].packetEvent(pevent);
                    }
                }
                catch (InvalidCastException e)
                {
                    Debug.WriteLine(e.Message);
                }
            }
		   // i++;
	    }

        /**
	     * 发送数据
	     */
        public void send()
        {
            OutPacket packet = null;
            if (0 == sendList.Count)
            {
                return;
            }
            else
            {
                packet = sendList.Peek();
                // Debug.WriteLine("MMessageID.C2U_REQ_ENTER_ROOM is sending");
                if (packet != null && packet.isNeedReply() && !packet.isSend())
                {
                    sendList.Dequeue();
                    byte[] data = packet.getData();
                    if (tcp != null)
                    {
                        packet.setSend(true);
                        try
                        {
                            tcp.send(data, 0, data.Length);
                            // startTimeout();
                        }
                        catch (Exception ex)
                        {
                            //throw ex;
                            ERROR_PACKET pp = new ERROR_PACKET(ERROR_PACKET.ERROR_CONNECT_EXCEPTION);
                            receive(pp);
                        }
                    }
                }
                else if (!packet.isNeedReply())
                {
                    while ((packet = sendList.Peek()) != null)
                    {
                        //发送
                        {
                            sendList.Dequeue();
                            byte[] data = packet.getData();
                            if (tcp != null)
                            {
                                try
                                {
                                    tcp.send(data, 0, data.Length);
                                }
                                catch (Exception ex)
                                {
                                    //throw ex;
                                    ERROR_PACKET pp = new ERROR_PACKET(ERROR_PACKET.ERROR_CONNECT_EXCEPTION);
                                    receive(pp);
                                }
                            }
                        }
                        if (0 == sendList.Count) break;
                    }
                }
            }
        }

        /**
	     * 接收数据包
	     * @param inPacket
	     */
        public void receive(InPacket inPacket)
        {
            //TCPPackage send = sendList.Peek();
            //判断是不是回复包
            //if (send != null && send.isNeedReply() && inPacket.getReplyID() == send.getMsgID())
            //{
                //sendList.Dequeue();
                //收到回复包重置超时时间
                //cancelTimeout();
                //sendExcutor.submit(new WaitCallback(SendCall));
               // this.send();
            //}
            receiveEvent.WaitOne();
            receiveEvent.Reset();

            putIn(inPacket);
            receiveExcutor.submit(new WaitCallback(ReceiveCall));

            receiveEvent.Set();
        }

        private void SendCall(object state)
        {
            sendEvent.WaitOne();
            sendEvent.Reset();

            this.send();

            sendEvent.Set();
        }

        private void ReceiveCall(object state)
        {
            receiveEvent.WaitOne();
            receiveEvent.Reset();

            triggerReceive();

            receiveEvent.Set();
        }

        /**
	     * 放到接收队列
	     * @param packet
	     */
        public void putIn(InPacket packet)
        {
            try
            {
                receiveList.Enqueue(packet);
            }
            catch (InvalidCastException e)
            {
                Debug.WriteLine(e.Message);
            }
        }

        /**
	     * 清空队列
	     */
	    public void clear(){
		    sendList.Clear();
		    receiveList.Clear();
	    }

        public void onError(int errorCode)
        {
            Debug.WriteLine("断开连接，清空队列");
            clear();
        }

        public virtual void packetEvent(PacketEvent pevent)
        {
		    InPacket packet = pevent.myPacket;
		    if(packet == null){
			    return;
		    }
		    if(packet is ERROR_PACKET){
                onError(((ERROR_PACKET)packet).getErrorCode());
		    }
	    }

        
    }
}
